今天稍加調整了一下三十天目標,把 DAY1 的標題做了一下修改,並把正式對輻狀基底函數類神經網路的介紹擺在了 DAY3 並且把梯度下降法的介紹拿掉,因為我覺得梯度下降法網路上文章很多了,也算是類神經網路中的基本知識。我還是想花多一點時間著墨於應用場景,還有一些觀念問題,請原諒我的私心吧。
我們在 DAY1 與 DAY2 花了許多時間談了輻狀基底函數,輻狀基底函數就是在資料中去選擇好多中心點,由這些中心點來對我們的資料進行訊息的擷取,中心點越多能攔截到越多的資訊,但是也可能會過度解釋。今天我們終於把基本的一些觀念搞清楚,可以來碰程式碼。
一個輻狀基底函數類神經網路,就是我們選了很多個中心點出來,然後透過中心點將資料中的訊息擷取出來,資料越接近中心點的話訊息強度就越強,反之若資料離中心點越遠的話,對這個中心點來說就是越沒有訊號。如果有這樣的概念,我們就可以來看一個輻狀基底函數的類神經網路架構圖:
後面都會以這個架構為主,也就是一層輻狀基底函數組成的隱藏層,然後有4個中心點,資料輸入為3個維度,輸出1個維度,有對應的標籤資料可以計算誤差值,這邊我們延續 DAY2 選擇高斯函數並且傳遞函數選 sigmoid,輸入與標籤資料我們都會先經過一個轉換,確保他是介在 0 至 1 之間,關於這點資料預處理在未來會談到。
好,MATLAB 手刻之程式碼如下,未來我們會在這個程式碼前後不斷加上啟發式演算法,或作微調,所以這個程式碼就像是原始材料一樣,接下來會分階段來說明,只要把所有程式碼前後兜起來就可以用了。
首先我們開了一個 m 檔案,建立一個 MATLAB 函數,輸入與輸出很明確,後綴採用 vector 與 matrix 方便後續討論。
% 輸入
% inputVector 為輸入資料( 1 x 資料維度 )
% centerMatrix 為中心點矩陣( 資料維度 x 中心點數量 )
% weightVector 為輸出層權重向量 ( 1 x 中心點數量 )
% 輸出
% outputVector 為計算後之輸出值 ( 1 x 1 )
function outputVector = RBFNN( inputVector, centerMatrix )
這邊可以注意到,我沒有把輻狀寬度的計算當作輸入擺進來,也就是說每次中心點進來之後我才會依照中心做輻狀寬度的計算,這個沒有什麼好壞,看每個人習慣,後續啟發式演算法我們不會著墨太多關於輻狀寬度的選擇,所以不把它作為獨立輸入,而用一段程式碼做計算。
% 基本設置 ------------------------------------------------------------
sizeCenter = size( centerMatrix ); % 取得中心矩陣的大小
nCenter = sizeCenter(2); % 中心點數量,原則上為 4
centerDistance = zeros( 1, nCenter ); % 中心點彼此距離,為了計算輻狀寬度而用
width = zeros( 1, nCenter ); % 依據中心點數值,產生輻狀寬度
RBFVector = zeros( 1, nCenter ); % 為了擺之後資料計算後的 RBF 值
weightVector = ones(1, nCenter); % 輸出層權重,這邊採全部為 1 固定值
biasValue = 0 ; % 輸出層偏置,不設定偏置採 0 固定值
這邊我們做了一些基本設置,變數的宣告都在這邊,可以注意到我在程式碼中輸出層的權重我都採1,偏置採0,原因我後面會提到,基本上輸出層的權重和偏置的計算方式,會成為未來我們在對中心點做啟發式搜尋的時候的難易控制,如果我們不調整輸出層的權重,意味著我們的啟發式演算法會在一個惡劣的條件下進行搜尋,因為輸出值幾乎和標籤值沒什麼關係。
但是如果我們將輸出層的權重採用 Batch Learning,讓輸出層的權重會盡量計算出來和標籤值接近,這樣子我們中心點的選擇就會在一個簡單的情況下搜尋,我現在這樣講你可能不會明白,後續我會再多做說明。簡單來說,當類神經網路搭配啟發式演算法做訓練的時候,如果我們盡量把一些我們不會去做優化的參數做定值,就會越加大我們搜尋的困難度,然而如果我們有些參數先針對問題做了一些優化, 我們搜尋的難度就會降低,但也可能會落入過擬合的情況!
我個人的經驗是,啟發式演算法的搜索能力很不錯,可以盡可能地在惡劣的環境做優化,也就是在隨機的情況做優化,如果有成本考量(例如時間限制或是資源限制)才會去另外優化一些我們不會在啟發式搜尋中優化的參數。
接下來是計算 RBF 值:
for iCenter = 1 : nCenter
% 計算中心點寬度 ---------------------------------------------------
% 選定一中心點 iCenter 計算與其他中心點 jCenter 的彼此距離( Norm )
for jCenter = 1 : nCenter
centerDistance(jCenter) = norm( centerMatrix(:,iCenter) - centerMatrix(:, jCenter) );
end % jCenter loop
% 檢查是否所有中心點距離為零(初始化中心點全部重疊)
if ~isempty(centerDistance(centerDistance ~= 0))
% 中心點計算公式:中心點距離最大值除以根號之中心點個數(重疊不算)
centerDistance = centerDistance(centerDistance ~= 0);
width(iCenter) = max(centerDistance)/sqrt(nCenter);
else
% 若所有中心點距離皆為零,報錯
error('All centers are same.');
end
% 計算 RBF 值 -----------------------------------------------------
RBFVector(iCenter) = exp(-(sqrt(sum((inputVector-centerMatrix(:,iCenter)').^2))/width(iCenter))^2 );
end % iCenter loop
最後就是輸出層與 Sigmoid 函數的計算。
% 輸出層權重採固定值(也就是沒有特別權重)-----------------------------
weightedVector = RBFVector * weightVector' + biasValue ;
% 使用 sigmoid 函數傳遞 -------------------------------------------
outputVector = 1 / ( 1 + exp( - weightedVector ) );
end
從 2010 年開始做類神經網路的開發工作到現在,我是萬萬沒想到類神經網路現在會這麼紅,想聊一些古早以前的故事之後再說吧,總而言之,輻狀基底類神經網路是一個我認為在傳統基本的類神經網路中,拿來應用在時間序列資料上非常好用的一個類神經網路,我知道有些朋友會提到說,RNN 能考量時域的特性不是更好嗎?沒錯,但是 RNN 最大實務上的麻煩,除了訓練時間長,就是他對於含噪音的資料比較不好處理(事實上訓練時間長已經讓我覺得有點麻煩了)
題外話,RNN 在處理資料上有些文章會建議先對資料進行去噪,然而一旦我們在對資料進行去噪的過程,往往也會造成滯後,這點我們在未來也會來探討,例如對資料進行移動平均去噪,往往也會造成他的滯後,這點對於不太能承受延遲風險的類神經網路模型來說會造成不少壓力。
關於延遲風險的部分可以看在 IThome 我的另外一篇不在鐵人賽的文章,或是未來我們在困境的章節會討論。